//------------------------------------------------------------------------------
// The contents of this file are subject to the nopCommerce Public License Version 1.0 ("License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at  http://www.nopCommerce.com/License.aspx. 
// 
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. 
// See the License for the specific language governing rights and limitations under the License.
// 
// The Original Code is nopCommerce.
// The Initial Developer of the Original Code is NopSolutions.
// All Rights Reserved.
// 
// Contributor(s): _______. 
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using Tathata.Common.Caching;
using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Data.Common;
using System.Data;
using System.Globalization;
using Tathata.Common.DAL;
using Tathata.Common.BLL.Entities;
using Tathata.Common.BLL.EntityCollections;
using Tathata.Common.DAL.Managers;

namespace Tathata.Common.BLL.Managers
{
    /// <summary>
    /// Discount manager
    /// </summary>
    public class DiscountManager
    {
        #region Constants
        private const string DISCOUNTS_ALL_KEY = "Nop.discount.all-{0}";
        private const string DISCOUNTS_BY_ID_KEY = "Nop.discount.id-{0}";
        private const string DISCOUNTS_BY_PRODUCTVARIANTID_KEY = "Nop.discount.byproductvariantid-{0}-{1}";
        private const string DISCOUNTS_BY_CUSTOMERROLEID_KEY = "Nop.discount.bycustomerroleid-{0}-{1}";
        private const string DISCOUNTS_BY_CATEGORYID_KEY = "Nop.discount.bycategoryid-{0}-{1}";
        #endregion

        #region Methods
        
        /// <summary>
        /// Gets a preferred discount
        /// </summary>
        /// <param name="CustomerID">Customer identifier</param>
        /// <param name="ProductVariantID">Product variant identifier</param>
        /// <returns>Discount</returns>
        public static Discount GetPreferredDiscount(int CustomerID, int ProductVariantID)
        {
            Discount preferredDiscount = null;

            ProductVariant productVariant = ProductVariantManager.GetByProductVariantID(ProductVariantID);
            if (productVariant == null)
                return preferredDiscount;

            DiscountCollection allowedDiscounts = new DiscountCollection();

            foreach (Discount _discount in productVariant.Discounts)
                if (_discount.IsActiveNow && !allowedDiscounts.ContainsDiscount(_discount.Name))
                    allowedDiscounts.Add(_discount);

            CustomerRoleCollection customerRoles = CustomerRoleManager.GetCustomerRolesByCustomerID(CustomerID);
            foreach (CustomerRole _customerRole in customerRoles)
                foreach (Discount _discount in _customerRole.Discounts)
                    if (_discount.IsActiveNow && !allowedDiscounts.ContainsDiscount(_discount.Name))
                        allowedDiscounts.Add(_discount);

            ProductCategoryCollection productCategories = ProductCategoryManager.GetProductCategoriesByProductID(productVariant.ProductID);
            foreach (ProductCategory _productCategory in productCategories)
            {
                Category category = _productCategory.Category;
                if (category != null)
                    foreach (Discount _discount in category.Discounts)
                        if (_discount.IsActiveNow && !allowedDiscounts.ContainsDiscount(_discount.Name))
                            allowedDiscounts.Add(_discount);
            }
            decimal maximumDiscountValue = decimal.Zero;
            foreach (Discount _discount in allowedDiscounts)
            {
                decimal currentDiscountValue = _discount.GetDiscountAmmount(productVariant.FinalPriceWithoutDiscount, false);
                if (currentDiscountValue > maximumDiscountValue)
                {
                    maximumDiscountValue = currentDiscountValue;
                    preferredDiscount = _discount;
                }
            }

            return preferredDiscount;
        }
        
        /// <summary>
        /// Gets a discount
        /// </summary>
        /// <param name="DiscountID">Discount identifier</param>
        /// <returns>Discount</returns>
        public static Discount GetByDiscountID(int DiscountID)
        {
            string key = string.Format(DISCOUNTS_BY_ID_KEY, DiscountID);
            object obj2 = NopCache.Get(key);
            if (NopContext.IsCachable && (obj2 != null))
            {
                return (Discount)obj2;
            }
            Discount discount = DiscountDBManager.GetByDiscountID(DiscountID);
            if (NopContext.IsCachable)
            {
                NopCache.Max(key, discount);
            }
            return discount;
        }

        /// <summary>
        /// Marks discount as deleted
        /// </summary>
        /// <param name="DiscountID">Discount identifier</param>
        public static void MarkDiscountAsDeleted(int DiscountID)
        {
            Discount discount = GetByDiscountID(DiscountID);
            if (discount != null)
            {
                UpdateDiscount(discount.DiscountID, discount.Name, discount.UsePercentage, discount.DiscountPercentage,
                    discount.DiscountAmount, discount.StartDate, discount.EndDate, true);
            }
            if (NopContext.IsCachable)
            {
                NopCache.RemoveByPattern(DISCOUNTS_ALL_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_ID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_PRODUCTVARIANTID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CUSTOMERROLEID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CATEGORYID_KEY);
            }
        }

        /// <summary>
        /// Gets all discounts
        /// </summary>
        /// <returns>Discount collection</returns>
        public static DiscountCollection GetAllDiscounts()
        {
            bool showHidden = NopContext.Current.IsAdmin;
            string key = string.Format(DISCOUNTS_ALL_KEY, showHidden);
            object obj2 = NopCache.Get(key);
            if (NopContext.IsCachable && (obj2 != null))
            {
                return (DiscountCollection)obj2;
            }

            DiscountCollection discountCollection = DiscountDBManager.GetAllDiscounts(showHidden);
            if (NopContext.IsCachable)
            {
                NopCache.Max(key, discountCollection);
            }
            return discountCollection;
        }

        /// <summary>
        /// Inserts a discount
        /// </summary>
        /// <param name="Name">The name</param>
        /// <param name="UsePercentage">A value indicating whether to use percentage</param>
        /// <param name="DiscountPercentage">The discount percentage</param>
        /// <param name="DiscountAmount">The discount amount</param>
        /// <param name="StartDate">The discount start date and time</param>
        /// <param name="EndDate">The discount end date and time</param>
        /// <param name="Deleted">A value indicating whether the entity has been deleted</param>
        /// <returns>Discount</returns>
        public static Discount InsertDiscount(string Name, bool UsePercentage, decimal DiscountPercentage, decimal DiscountAmount,
            DateTime StartDate, DateTime EndDate, bool Deleted)
        {
            if (StartDate.CompareTo(EndDate) >= 0)
                throw new Exception("StartDate should be less then EndDate");

            Discount discount = DiscountDBManager.InsertDiscount(Name, UsePercentage, DiscountPercentage, DiscountAmount,
             StartDate, EndDate, Deleted);
            if (NopContext.IsCachable)
            {
                NopCache.RemoveByPattern(DISCOUNTS_ALL_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_ID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_PRODUCTVARIANTID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CUSTOMERROLEID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CATEGORYID_KEY);
            }
            return discount;
        }

        /// <summary>
        /// Updates the discount
        /// </summary>
        /// <param name="DiscountID">Discount identifier</param>
        /// <param name="Name">The name</param>
        /// <param name="UsePercentage">A value indicating whether to use percentage</param>
        /// <param name="DiscountPercentage">The discount percentage</param>
        /// <param name="DiscountAmount">The discount amount</param>
        /// <param name="StartDate">The discount start date and time</param>
        /// <param name="EndDate">The discount end date and time</param>
        /// <param name="Deleted">A value indicating whether the entity has been deleted</param>
        /// <returns>Discount</returns>
        public static Discount UpdateDiscount(int DiscountID, string Name, bool UsePercentage, decimal DiscountPercentage, decimal DiscountAmount,
            DateTime StartDate, DateTime EndDate, bool Deleted)
        {
            if (StartDate.CompareTo(EndDate) >= 0)
                throw new Exception("StartDate should be less then EndDate");
            Discount discount = DiscountDBManager.UpdateDiscount(DiscountID, Name, UsePercentage, DiscountPercentage, DiscountAmount,
             StartDate, EndDate, Deleted);
            if (NopContext.IsCachable)
            {
                NopCache.RemoveByPattern(DISCOUNTS_ALL_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_ID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_PRODUCTVARIANTID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CUSTOMERROLEID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CATEGORYID_KEY);
            }
            return discount;
        }

        /// <summary>
        /// Adds a discount to a product variant
        /// </summary>
        /// <param name="ProductVariantID">Product variant identifier</param>
        /// <param name="DiscountID">Discount identifier</param>
        public static void AddDiscountToProductVariant(int ProductVariantID, int DiscountID)
        {
            DiscountDBManager.AddDiscountToProductVariant(ProductVariantID, DiscountID);
            if (NopContext.IsCachable)
            {
                NopCache.RemoveByPattern(DISCOUNTS_ALL_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_ID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_PRODUCTVARIANTID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CUSTOMERROLEID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CATEGORYID_KEY);
            }
        }

        /// <summary>
        /// Removes a discount from a product variant
        /// </summary>
        /// <param name="ProductVariantID">Product variant identifier</param>
        /// <param name="DiscountID">Discount identifier</param>
        public static void RemoveDiscountFromProductVariant(int ProductVariantID, int DiscountID)
        {
            DiscountDBManager.RemoveDiscountFromProductVariant(ProductVariantID, DiscountID);
            if (NopContext.IsCachable)
            {
                NopCache.RemoveByPattern(DISCOUNTS_ALL_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_ID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_PRODUCTVARIANTID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CUSTOMERROLEID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CATEGORYID_KEY);
            }
        }

        /// <summary>
        /// Gets a discount collection of a product variant
        /// </summary>
        /// <param name="ProductVariantID">Product variant identifier</param>
        /// <returns>Discount collection</returns>
        public static DiscountCollection GetDiscountsByProductVariantID(int ProductVariantID)
        {
            bool showHidden = NopContext.Current.IsAdmin;
            string key = string.Format(DISCOUNTS_BY_PRODUCTVARIANTID_KEY, ProductVariantID, showHidden);
            object obj2 = NopCache.Get(key);
            if (NopContext.IsCachable && (obj2 != null))
            {
                return (DiscountCollection)obj2;
            }

            DiscountCollection discountCollection = DiscountDBManager.GetDiscountsByProductVariantID(ProductVariantID, showHidden);
            if (NopContext.IsCachable)
            {
                NopCache.Max(key, discountCollection);
            }
            return discountCollection;
        }

        /// <summary>
        /// Adds a discount to a customer role
        /// </summary>
        /// <param name="CustomerRoleID">Customer role identifier</param>
        /// <param name="DiscountID">Discount identifier</param>
        public static void AddDiscountToCustomerRole(int CustomerRoleID, int DiscountID)
        {
            DiscountDBManager.AddDiscountToCustomerRole(CustomerRoleID, DiscountID);
            if (NopContext.IsCachable)
            {
                NopCache.RemoveByPattern(DISCOUNTS_ALL_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_ID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_PRODUCTVARIANTID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CUSTOMERROLEID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CATEGORYID_KEY);
            }
        }

        /// <summary>
        /// Removes a discount from a customer role
        /// </summary>
        /// <param name="CustomerRoleID">Customer role identifier</param>
        /// <param name="DiscountID">Discount identifier</param>
        public static void RemoveDiscountFromCustomerRole(int CustomerRoleID, int DiscountID)
        {
            DiscountDBManager.RemoveDiscountFromCustomerRole(CustomerRoleID, DiscountID);
            if (NopContext.IsCachable)
            {
                NopCache.RemoveByPattern(DISCOUNTS_ALL_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_ID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_PRODUCTVARIANTID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CUSTOMERROLEID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CATEGORYID_KEY);
            }
        }

        /// <summary>
        /// Gets a discount collection of a customer role
        /// </summary>
        /// <param name="CustomerRoleID">Customer role identifier</param>
        /// <returns>Discount collection</returns>
        public static DiscountCollection GetDiscountsByCustomerRoleID(int CustomerRoleID)
        {
            bool showHidden = NopContext.Current.IsAdmin;
            string key = string.Format(DISCOUNTS_BY_CUSTOMERROLEID_KEY, CustomerRoleID, showHidden);
            object obj2 = NopCache.Get(key);
            if (NopContext.IsCachable && (obj2 != null))
            {
                return (DiscountCollection)obj2;
            }

            DiscountCollection discountCollection = DiscountDBManager.GetDiscountsByCustomerRoleID(CustomerRoleID, showHidden);
            if (NopContext.IsCachable)
            {
                NopCache.Max(key, discountCollection);
            }
            return discountCollection;
        }

        /// <summary>
        /// Adds a discount to a category
        /// </summary>
        /// <param name="CategoryID">Category identifier</param>
        /// <param name="DiscountID">Discount identifier</param>
        public static void AddDiscountToCategory(int CategoryID, int DiscountID)
        {
            DiscountDBManager.AddDiscountToCategory(CategoryID, DiscountID);
            if (NopContext.IsCachable)
            {
                NopCache.RemoveByPattern(DISCOUNTS_ALL_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_ID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_PRODUCTVARIANTID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CUSTOMERROLEID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CATEGORYID_KEY);
            }
        }

        /// <summary>
        /// Removes a discount from a category
        /// </summary>
        /// <param name="CategoryID">Category identifier</param>
        /// <param name="DiscountID">Discount identifier</param>
        public static void RemoveDiscountFromCategory(int CategoryID, int DiscountID)
        {
            DiscountDBManager.RemoveDiscountFromCategory(CategoryID, DiscountID);
            if (NopContext.IsCachable)
            {
                NopCache.RemoveByPattern(DISCOUNTS_ALL_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_ID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_PRODUCTVARIANTID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CUSTOMERROLEID_KEY);
                NopCache.RemoveByPattern(DISCOUNTS_BY_CATEGORYID_KEY);
            }
        }

        /// <summary>
        /// Gets a discount collection of a category
        /// </summary>
        /// <param name="CategoryID">Category identifier</param>
        /// <returns>Discount collection</returns>
        public static DiscountCollection GetDiscountsByCategoryID(int CategoryID)
        {
            bool showHidden = NopContext.Current.IsAdmin;
            string key = string.Format(DISCOUNTS_BY_CATEGORYID_KEY, CategoryID, showHidden);
            object obj2 = NopCache.Get(key);
            if (NopContext.IsCachable && (obj2 != null))
            {
                return (DiscountCollection)obj2;
            }

            DiscountCollection discountCollection = DiscountDBManager.GetDiscountsByCategoryID(CategoryID, showHidden);
            if (NopContext.IsCachable)
            {
                NopCache.Max(key, discountCollection);
            }
            return discountCollection;
        }
        #endregion
    }
}
